/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"

#include "OBJ模型加载保存.h"
#include "面/面.h"
#include "材质/材质.h"

#include <file_载入保存数据.h>
#include <file_文件名数据.h>
#include <字符串/str_字符串读写.h>

#include "底层绘图/S_纹理.h"



#define MAX_LINE_LENGTH 1024



typedef struct {
	S_材质管线* 材质;
	uint32  槽;
}S_材质和槽;




static void f_读顶点(std::vector<std::string>& 行信息, std::vector<vec3>& vert) {
	vec3 v;
	v.x = atof(行信息[0].c_str());
	v.y = atof(行信息[1].c_str());
	v.z = atof(行信息[2].c_str());
	vert.emplace_back(v);
}

static void f_读纹理坐标(std::vector<std::string>& 行信息, std::vector<vec2>& uv) {
	vec2 v;
	v.x = atof(行信息[0].c_str());
	v.y = atof(行信息[1].c_str());
	uv.emplace_back(v);
}

static void f_读索引(std::vector<std::string>& 行信息, std::vector<uint32>& index) {
	uint32 num = 行信息.size();
	for (uint32 i = 0; i < num; ++i) {
		std::vector<std::string> 索引;
		f_str_分割(索引, 行信息[i], '/');

		for (auto& e : 索引) {
			index.emplace_back(atoi(e.c_str()));
		}
	}
}

static void f_分离索引(std::vector<uint32>& index, std::vector<uint32>& v_index, std::vector<uint32>& uv_index) {
	uint32 num = index.size() / 2;
	auto index_p = index.data();

	v_index.resize(num);
	uv_index.resize(num);
	auto vi_p = v_index.data();
	auto ui_p = uv_index.data();
	for (uint32 i = 0; i < num; ++i) {
		vi_p[i] = index_p[i * 2] - 1;
		ui_p[i] = index_p[i * 2 + 1] - 1;
	}
}

static void f_分离索引(std::vector<uint32>& index, std::vector<uint32>& v_index, std::vector<uint32>& uv_index, std::vector<uint32>& n_index) {
	uint32 num = index.size() / 3;
	auto index_p = index.data();

	v_index.resize(num);
	uv_index.resize(num);
	n_index.resize(num);
	auto vi_p = v_index.data();
	auto ui_p = uv_index.data();
	auto ni_p = n_index.data();
	for (uint32 i = 0; i < num; ++i) {
		vi_p[i] = index_p[i * 3] - 1;
		ui_p[i] = index_p[i * 3 + 1] - 1;
		ni_p[i] = index_p[i * 3 + 2] - 1;
	}
}

static void f_加载材质(S_设备环境& ctx, std::map<std::string, S_材质和槽>& 材质组, std::vector<S_纹理添加列队>& 纹理加载列队, const std::string& 材质文件路径) {
	FILE* f = fopen(材质文件路径.c_str(), "rb");
	if (f) {
		char line[MAX_LINE_LENGTH];

		S_材质管线* mtl = nullptr;

		while (fgets(line, MAX_LINE_LENGTH, f)) {
			if (strncmp(line, "newmtl", 6) == 0) {
				std::string 材质名称("", 256);
				sscanf(line, "newmtl %s", 材质名称.data());

				mtl = f_material_createPBR();
				材质组[材质名称] = { mtl, uint32(材质组.size()) };
			}
			//环境光颜色
			else if (strncmp(line, "Ka", 2) == 0) {
				vec3 环境光;
				sscanf(line, "Ka %f %f %f", &环境光.x, &环境光.y, &环境光.z);
			}
			//漫反射颜色
			else if (strncmp(line, "Kd", 2) == 0) {

			}
			//镜面反射颜色
			else if (strncmp(line, "Ks", 2) == 0) {

			}
			//光泽度
			else if (strncmp(line, "Ns", 2) == 0) {

			}
			//透明度
			else if (strncmp(line, "d", 1) == 0) {

			}
			//自发光
			else if (strncmp(line, "illum", 5) == 0) {
				float32 自发光 = 0;
				sscanf(line, "Ns %f", &自发光);
			}
			else if (strncmp(line, "map_Kd ", 6) == 0) {
				std::string 纹理名称("", 256);
				sscanf(line, "map_Kd %s", 纹理名称.data());

				//auto 纹理 = f_tex_创建图像(ctx, { 8,8,1 }, E_纹理格式::e_tf_RGBA8U_归一化, E_纹理维度类型::e_2D);
				//纹理加载列队.push_back({ 纹理名称, 纹理, nullptr });
			}
		}

		fclose(f);
	}
}

//S_物体* f_Ex加载OBJ模型(const std::string& path, S_设备环境& ctx) {
//	S_物体* ob = new S_物体(E_物体类型::t_多边形);
//	f_ob_创建矩阵(ob);
//	f_ob_set数据槽数量(ob, 1);
//
//	f_Ex加载OBJ模型(ob, path, ctx);
//	return ob;
//}

void f_Ex加载OBJ模型(S_物体* ob, const std::string& path, S_设备环境& ctx, std::vector<S_纹理添加列队>& 纹理加载列队) {
	#define MAX_LINE_LENGTH 1024
	char line[MAX_LINE_LENGTH];

	auto 文件名 = f_file_get无后缀文件名(path);
	auto 材质文件路径 = f_file_get路径(path) + 文件名 + ".mtl";
	
	std::map<std::string, S_材质和槽> 材质组;
	std::map<std::string, uint32> 材质;
	f_加载材质(ctx, 材质组, 纹理加载列队, 材质文件路径);


	std::vector<vec3> vert;
	std::vector<vec3> normal;
	std::vector<vec2> uv;


	FILE* f = fopen(path.c_str(), "rb");
	if (f) {
		switch (ob->m_Type) {
			case E_物体类型::t_多边形: {

				S_多边形* 多边形 = f_ob_from多边形(ob);

			
				
				//S_Mesh* me = f_surface_创建网格对象(ctx, E_网格数据枚举::e_Mesh_VULKAN);
				//std::string code = f_读取字符串(f);
				//uint32 num = code.size();
				//auto codePtr = code.data();
				//auto codePtr = code.c_str();
				std::vector<uint32> 纹理索引;
				
				//std::vector<uint32> mal;

				std::vector<S_VNT1> vnt;

				//vert = { {1.000000, 0.000000, -1.000000}, {-1.000000, 0.000000, -1.000000}, {1.000000, 0.000000, 1.000000}, {-1.000000, 0.000000, 1.000000} };
				//normal = { {0.0000, 1.0000, 0.0000}, {0.0000, 1.0000, 0.0000}, {0.0000, 1.0000, 0.0000}, {0.0000, 1.0000, 0.0000} };
				//uv = {{1.000000, 0.000000}, {0.000000, 1.000000}, {0.000000, 0.000000}, {1.000000, 1.000000}};
				//std::vector<uint32> v_index = {2-1,3 - 1,1 - 1,2 - 1,4 - 1,3 - 1 };
				//f_surface_数组合并(vnt, vert, vert, uv);
				//f_surface_fill顶点数据(me, vnt);
				//f_surface_fill索引数据(me, v_index);
				//ob->m_Bound = f_surface_计算包围盒(me);
				//fclose(f);
				//return;
				uint32 材质ID = 0;
				

				S_多边形元素* 元素 = nullptr;

				while (fgets(line, MAX_LINE_LENGTH, f)) {
					if (strncmp(line, "v ", 2) == 0) {
						vec3 v;
						sscanf(line, "v %f %f %f", &v.x, &v.y, &v.z);
						vert.push_back(v);
					}
					else if (strncmp(line, "vn ", 3) == 0) {
						vec3 vn;
						sscanf(line, "vn %f %f %f", &vn.x, &vn.y, &vn.z);
						normal.push_back(vn);
					}
					else if (strncmp(line, "vt ", 3) == 0) {
						vec2 vt;
						sscanf(line, "vt %f %f", &vt.x, &vt.y);
						uv.push_back(vt);
					}
					else if (strncmp(line, "f ", 2) == 0) {

						//std::vector<uint32> vIndex;
						//std::vector<uint32> uv索引;
						//std::vector<uint32> 法线索引;
						std::vector<uint32> 顶点索引;
						uvec2 loopUV{};
						loopUV.x = 纹理索引.size();


						const char* cursor = line + 2;

						uint32 i = 0;
						for (; i < 4096 * 2; ++i) {
							uint32 vIndex = 0, uv索引 = 0, 法线索引 = 0;

							if (sscanf(cursor, "%u/%u/%u", &vIndex, &uv索引, &法线索引) == 3) {
								顶点索引.push_back(vIndex - 1);
								纹理索引.push_back(uv索引 - 1);
							}
							else if (sscanf(cursor, "%d//%d", &vIndex, &法线索引) == 2) {
								顶点索引.push_back(vIndex - 1);
								纹理索引.push_back(uv索引 - 1);
							}
							else if (sscanf(cursor, "%d/%d", &vIndex, &uv索引) == 2) {
								顶点索引.push_back(vIndex - 1);
							}
							else if (sscanf(cursor, "%d", &vIndex) == 1) {
								顶点索引.push_back(vIndex - 1);
							}
							else {
								break;
							}
							while (*(cursor++) != ' ' && *cursor != '\0' && *cursor != '\r');
						}
						loopUV.y = 纹理索引.size();

						//index.push_back(顶点索引[0]); index.push_back(uv索引[1]); index.push_back(法线索引[2]);
						//index.push_back(顶点索引[0]); index.push_back(uv索引[1]); index.push_back(法线索引[2]);
						S_面* 面 = f_surface_添加多边形面(多边形, 顶点索引.data(), 顶点索引.size());

						if (!元素) {
							元素 = (S_多边形元素*)f_core_array_new(0, sizeof(S_面*));
							f_core_array_push_back((S_Array*)多边形->m_元素组, (uint8*)&元素);
						}

						面->polygon = (S_结构指针)多边形;
						面->vertIndex = 顶点索引;
						面->uvLoopIndex.push_back(loopUV);
						面->材质槽 = 材质ID;
						面->ID = 元素->count;


						f_core_array_push_back((S_Array*)元素, (uint8*)&面);
						//材质槽.push_back(材质ID);
					}
					else if (strncmp(line, "usemtl", 6) == 0) {
						std::string 纹理名称("", 256);
						sscanf(line, "usemtl %s", 纹理名称.data());

						if (材质组.find(纹理名称) != 材质组.end()) {
							材质ID = 材质组[纹理名称].槽;
						}
						else {
							//材质ID = 材质.size();
							//材质[strArray.front()] = 材质ID;
						}

						元素 = (S_多边形元素*)f_core_array_new(0, sizeof(S_面*));
						f_core_array_push_back((S_Array*)多边形->m_元素组, (uint8*)&元素);
					}
				}

				fclose(f);

				uint32 flage = 0;
				if (vert.size()) flage |= 1 << 0;
				if (normal.size()) flage |= 1 << 1;
				if (uv.size()) flage |= 1 << 2;



				//f_surface_fill索引数据(me, 顶点索引);

				switch (flage) {
					case 1:
						多边形->m_顶点 = vert;
						break;
					case 3:
						//f_surface_数组合并(vnt, vert, normal);

						break;
					case 5: {
						多边形->m_顶点 = vert;
						多边形->m_UV = uv;
						多边形->m_UV索引 = 纹理索引;

						//f_surface_数组合并(vnt, vert);
						//f_surface_fill顶点数据(me, vnt);
						多边形->m_UV层数量 = 1;

						//f_surface_fill层纹理坐标(me, uv);
						//f_surface_fill纹理坐标索引(me, 纹理索引);

						break;
					}
					case 7: {
						多边形->m_顶点 = vert;
						多边形->m_UV = uv;
						多边形->m_UV索引 = 纹理索引;
						//f_surface_数组合并(vnt, vert, normal);
						//f_surface_fill顶点数据(me, vnt);

						多边形->m_UV层数量 = 1;


						//f_surface_fill层纹理坐标(me, uv);
						//f_surface_fill纹理坐标索引(me, 纹理索引);

						break;
					}
					default:
						break;
				}

				//f_surface_set材质ID(me, 材质槽);
				//if (mal.size()) {
				//	f_surface_set材质ID(me, mal);
				//}
				


				//ob->m_Bound = f_surface_计算包围盒(me);
				
				//f_ob_set数据(ob, me);
				break;
			}
			default: {
				S_Mesh* me = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_面);


				std::vector<S_VNT1> vnt;
				std::vector<uint32> 顶点索引;
				std::vector<uint32> 纹理索引;
				std::vector<uint32> 材质槽;
				
				uint32 材质ID = 0;


				S_多边形元素* 元素 = nullptr;

				while (fgets(line, MAX_LINE_LENGTH, f)) {
					if (strncmp(line, "v ", 2) == 0) {
						vec3 v;
						sscanf(line, "v %f %f %f", &v.x, &v.y, &v.z);
						vert.push_back(v);
					}
					else if (strncmp(line, "vn ", 3) == 0) {
						vec3 vn;
						sscanf(line, "vn %f %f %f", &vn.x, &vn.y, &vn.z);
						normal.push_back(vn);
					}
					else if (strncmp(line, "vt ", 3) == 0) {
						vec2 vt;
						sscanf(line, "vt %f %f", &vt.x, &vt.y);
						uv.push_back(vt);
					}
					else if (strncmp(line, "f ", 2) == 0) {

						//std::vector<uint32> vIndex;
						//std::vector<uint32> uv索引;
						//std::vector<uint32> 法线索引;
						
						const char* cursor = line + 2;

						uint32 i = 0;
						for (; i < 4096 * 2; ++i) {
							uint32 vIndex = 0, uv索引 = 0, 法线索引 = 0;

							if (sscanf(cursor, "%u/%u/%u", &vIndex, &uv索引, &法线索引) == 3) {
								顶点索引.push_back(vIndex - 1);
								纹理索引.push_back(uv索引 - 1);
							}
							else if (sscanf(cursor, "%d//%d", &vIndex, &法线索引) == 2) {
								顶点索引.push_back(vIndex - 1);
								纹理索引.push_back(uv索引 - 1);
							}
							else if (sscanf(cursor, "%d/%d", &vIndex, &uv索引) == 2) {
								顶点索引.push_back(vIndex - 1);
							}
							else if (sscanf(cursor, "%d", &vIndex) == 1) {
								顶点索引.push_back(vIndex - 1);
							}
							else {
								break;
							}
							while (*(cursor++) != ' ' && *cursor != '\0' && *cursor != '\r');
						}
						
						材质槽.push_back(材质ID);
					}
					else if (strncmp(line, "usemtl", 6) == 0) {
						std::string 纹理名称("", 256);
						sscanf(line, "usemtl %s", 纹理名称.data());

						if (材质组.find(纹理名称) != 材质组.end()) {
							材质ID = 材质组[纹理名称].槽;
						}
						else {
							//材质ID = 材质.size();
							//材质[strArray.front()] = 材质ID;
						}
					}
				}

				fclose(f);

				uint32 flage = 0;
				if (vert.size()) flage |= 1 << 0;
				if (normal.size()) flage |= 1 << 1;
				if (uv.size()) flage |= 1 << 2;



				//f_surface_fill索引数据(me, 顶点索引);
				switch (flage) {
					case 1:
						f_mesh_fill顶点数据(me, vert);
						break;
					case 3:
						//f_surface_数组合并(vnt, vert, normal);

						break;
					case 5: {
						f_surface_数组合并(vnt, vert, uv);
						f_mesh_fill顶点数据(me, vnt);
						
						f_surface_fill纹理坐标索引(me, 纹理索引);
						f_me_fill索引(me, 顶点索引);
						break;
					}
					case 7: {
						f_surface_数组合并(vnt, vert, normal, uv);
						f_mesh_fill顶点数据(me, vnt);

						f_surface_fill纹理坐标索引(me, 纹理索引);
						f_me_fill索引(me, 顶点索引);
						break;
					}
					default:
						break;
				}

				for (auto& e : 材质组) {
					f_me_set多维材质(me, e.second.材质, e.second.槽, e.second.槽);
				}
				break;
			}
		}

		ob->m_显示 = true;
		ob->m_isUpdate = true;
	}
	else {
		ob->m_显示 = false;
	}
	
	
}






//for (uint32 i = 0; *codePtr != '\0'; ) {
//	if (*codePtr == '#' || *codePtr == '\r') {
//		++codePtr;
//		codePtr = f_file_到下一行(codePtr);
//		continue;
//	}
//	else {
//		std::string 一行;
//		codePtr = f_str_读一行(codePtr, 一行);
//
//
//		if (一行.size()) {
//			std::vector<std::string> strArray;
//			f_str_分割(strArray, 一行, ' ');
//
//			//std::cout << "一行 = " << 一行 << std::endl;
//			auto h = strArray.front();
//			strArray.erase(strArray.begin());
//
//			if (h == "v") {
//				f_读顶点(strArray, vert);
//			}
//			else if (h == "vn") {
//				f_读顶点(strArray, normal);
//			}
//			else if (h == "vt") {
//				f_读纹理坐标(strArray, uv);
//			}
//			else if (h == "f") {
//				f_读索引(strArray, index);
//				mal.push_back(材质ID);
//			}
//			else if (h == "usematl") {
//				if(材质.find(strArray.front()) != 材质.end()) {
//					材质ID = 材质[strArray.front()];
//				}
//				else {
//					材质ID = 材质.size();
//					材质[strArray.front()] = 材质ID;
//				}
//			}
//		}
//
//		continue;
//	}
//
//	++i;
//}
